Feat/nitro35 support#586
Merged
Merged
Conversation
Add biome.json and migrate lint/format tooling from ESLint/Prettier to Biome (remove eslint/prettier configs and eslint.config.mts). Update package.json scripts to use biome (lint, lint:ci, format) and add Biome-related dev deps. Bump example and root package dependency versions (including react-native, react-native-nitro-modules, nitrogen, Babel and related tooling), add nkf to example/Gemfile, and update Android Gradle wrapper to 9.3.1 while simplifying gradle wrapper scripts (remove CLASSPATH handling).
Introduce a typed error surface and refactor async/hooks/storage plumbing for better safety and tree-shaking. Key changes: - Add src/errors.ts: typed SensitiveInfoError subclasses, ErrorCode constants, adapters (toSensitiveInfoError) and predicate helpers. - Wrap native calls in src/core/storage.ts to throw/return typed errors, and add rotateKeys and getKeyVersion; expose a SensitiveInfo namespace and named exports for tree-shaking. - Add useAsync abstraction (src/hooks/useAsync.ts) and refactor hooks (useHasSecret, useSecretItem, useSecurityAvailability) to use it. Add a new useKeyRotation hook. - Update hooks index exports to include new hooks and types. - Rework internal helpers: normalizeOptions improved and internal/errors re-exports updated to forward to the new typed helpers. - Add strong types file src/sensitive-info.nitro.ts and update top-level exports in src/index.ts to include errors and new storage APIs. - Add unit tests for errors and public index surface (src/__tests__/errors.test.ts, src/__tests__/index.test.ts). - package.json: add "exports" map and sideEffects:false, and align react-dom version. These changes modernize error handling, centralize async lifecycle management for hooks, and add support for key rotation while keeping backward-compatible exports.
Introduce versioned key rotation support and related developer ergonomics: add native stubs (rotateKeys, getKeyVersion) on Android, document the new useKeyRotation hook and imperative rotateKeys/getKeyVersion APIs, and wire a KeyRotationPanel into the example app. Update README and CHANGELOG for 6.0.0-rc.13, add hook docs in HOOKS.md, and include new tests for key rotation/hooks. Remove .prettierrc, apply consistent formatting/style updates across examples and components (node:path imports, minor TSX/JS formatting), and adjust expo/config plugin and other config files.
…nd update related components
- Added HMAC-SHA256 integrity tags to entries, enhancing tamper detection. - Introduced AES-GCM AAD for additional security against cross-entry attacks. - Implemented zeroization of plaintext buffers post-use on both platforms. - Updated error handling to include IntegrityViolationError for tampering cases. - Enhanced metadata structure to include integrity tags and AAD usage flags. - Updated tests to verify integrity tag propagation and error handling for integrity violations. Co-authored-by: Copilot <copilot@github.com>
Introduce a shared useAsyncQuery hook to centralize stable-options → skip → memoize → useAsync semantics and ensure consistent abort/skip behavior across hooks. Refactor useHasSecret and useSecretItem to use the new hook. Add deterministic test fixtures (buildTestItem/buildTestMetadata) and update unit tests to use them. Adjust error imports to prefer the public errors surface and remove legacy re-exports from src/internal/errors.ts. Bump package version to 6.0.0-rc.13. Files added: src/hooks/useAsyncQuery.ts, src/__tests__/__mocks__/fixtures.ts; files updated: multiple hooks, tests, and internal error helpers.
Co-authored-by: Copilot <copilot@github.com>
…uery integration Co-authored-by: Copilot <copilot@github.com>
Contributor
There was a problem hiding this comment.
Pull request overview
Note
Copilot was unable to run its full agentic suite in this review.
This PR prepares a 6.0.0 release candidate by adding versioned key rotation + integrity hardening, introducing typed errors and new hook primitives, and migrating project tooling to Biome while updating package exports for tree-shaking.
Changes:
- Added key rotation APIs (
rotateKeys,getKeyVersion) +useKeyRotationhook, plus typed error surface under/errors. - Implemented defense-in-depth integrity protections (per-entry HMAC tags, Android AAD binding, device-unlocked gating) and related metadata updates across platforms.
- Migrated formatting/linting to Biome and updated packaging/exports for side-effect-free, subpath-based consumption.
Reviewed changes
Copilot reviewed 92 out of 99 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| tsconfig.test.json | Adds Jest/Node types and streamlines include/exclude for tests. |
| tsconfig.json | Adds TS deprecation config and excludes tests from main compilation. |
| src/sensitive-info.nitro.ts | Extends Nitro spec/types with rotation requests/results and metadata fields. |
| src/internal/options.ts | Makes option normalization shape deterministic by pruning undefined. |
| src/internal/native.ts | Keeps native instance memoization while adopting Biome formatting. |
| src/internal/errors.ts | Removes marker predicates, keeping only message extraction helper. |
| src/index.ts | Re-exports core API + typed errors/types; removes default export behavior. |
| src/hooks/useStableOptions.ts | Formatting + retains memoized option merging implementation. |
| src/hooks/useSecurityAvailability.ts | Refactors to shared useAsync primitive with caching/refetch. |
| src/hooks/useSecureStorage.ts | Refactors to useAsyncQuery + useMutation composition. |
| src/hooks/useSecureOperation.ts | Refactors to useMutation with consistent loading/error behavior. |
| src/hooks/useSecretItem.ts | Refactors to useAsyncQuery shared fetch+skip wiring. |
| src/hooks/useSecret.ts | Keeps API but updates formatting and dependencies for refactor. |
| src/hooks/useMutation.ts | New shared mutation state machine (abort + auth-cancel + HookError). |
| src/hooks/useKeyRotation.ts | New hook wrapping rotateKeys/getKeyVersion with UI-ready state. |
| src/hooks/useHasSecret.ts | Refactors to useAsyncQuery shared fetch+skip wiring. |
| src/hooks/useAsyncQuery.ts | New shared “stable options → skip → memoize → useAsync” helper. |
| src/hooks/useAsyncLifecycle.ts | Formatting; keeps abort+mount guard utility. |
| src/hooks/useAsync.ts | New shared async state machine used by data-fetching hooks. |
| src/hooks/types.ts | Formatting; preserves HookError + async state/result helpers. |
| src/hooks/index.ts | Adds useKeyRotation export and reorganizes named exports. |
| src/hooks/error-utils.ts | Uses new public /errors predicate + internal message helper. |
| src/errors.ts | New typed error classes, codes, adapters, and predicates. |
| src/core/storage.ts | Wraps native throws into typed errors; adds rotate APIs. |
| src/tests/storage.test.ts | Adjusts formatting; keeps coverage for storage surface. |
| src/tests/internal.options.test.ts | Updates expectations for normalized/pruned options. |
| src/tests/internal.native.test.ts | Updates mocks + formatting for native instance memo tests. |
| src/tests/internal.errors.test.ts | Switches not-found checks to new /errors predicate. |
| src/tests/index.test.ts | Updates entrypoint expectations (no default export; new exports). |
| src/tests/hooks.useStableOptions.test.tsx | Formatting-only updates. |
| src/tests/hooks.useSecurityAvailability.test.tsx | Validates new useAsync-based hook behavior. |
| src/tests/hooks.useSecureOperation.test.tsx | Validates useMutation-based execute behavior. |
| src/tests/hooks.useSecretItem.test.tsx | Updates tests to fixture builders + new hook wiring. |
| src/tests/hooks.useSecret.test.tsx | Updates tests to match refactor and formatting. |
| src/tests/hooks.useKeyRotation.test.tsx | New tests for useKeyRotation. |
| src/tests/hooks.useHasSecret.test.tsx | Updates tests for refactored hook. |
| src/tests/hooks.useAsyncLifecycle.test.tsx | Formatting-only updates. |
| src/tests/hooks.types.test.ts | Formatting-only updates. |
| src/tests/hooks.index.test.ts | New test to validate hooks subpath re-exports. |
| src/tests/hooks.error-utils.test.ts | Formatting-only updates. |
| src/tests/errors.test.ts | New tests for typed errors/adapters/predicates. |
| src/tests/mocks/react-native.ts | Formatting-only updates for mocks. |
| src/tests/mocks/react-native-nitro-modules.ts | Formatting-only updates for mocks. |
| src/tests/mocks/fixtures.ts | New deterministic test fixtures for metadata/items. |
| release.config.cjs | Formatting-only updates for semantic-release config. |
| post-script.js | Formatting-only updates; retains Nitro Android workaround. |
| package.json | Adds exports + sideEffects:false, switches to Biome, updates deps. |
| nitro.json | Formatting-only updates to Nitro config. |
| jest.config.js | Formatting; adjusts coverage thresholds; keeps coverage collection. |
| ios/Internal/Security/MetadataIntegrity.swift | Adds per-entry HMAC integrity signing/verification. |
| ios/Internal/Security/KeyVersionRegistry.swift | Adds key version registry for iOS key rotation. |
| ios/Internal/MetadataCoders.swift | Persists key version + integrity tag in metadata coding. |
| ios/HybridSensitiveInfo.swift | Implements iOS key rotation + integrity verification + lazy upgrade. |
| example/tsconfig.json | Formatting-only updates. |
| example/src/utils/formatError.ts | Formatting-only updates. |
| example/src/constants/index.ts | Updates imports and formatting for new root API shape. |
| example/src/components/SecretsList.tsx | Formatting + type-only React import conversion. |
| example/src/components/SecretForm.tsx | Formatting + type-only React import conversion. |
| example/src/components/ModeSelector.tsx | Formatting + accessibility state maintained. |
| example/src/components/KeyRotationPanel.tsx | New example UI for rotation. |
| example/src/components/Header.tsx | Formatting + type-only React import conversion. |
| example/src/components/Card.tsx | Formatting + type-only React import conversion. |
| example/src/components/ActionsPanel.tsx | Formatting + type-only React import conversion. |
| example/src/components/ActionButton.tsx | Formatting + type-only React import conversion. |
| example/react-native.config.js | Updates to node: path import + formatting. |
| example/package.json | Updates RN/Nitro versions; switches lint to Biome. |
| example/metro.config.js | Updates to node: path import + formatting. |
| example/jest.config.js | Formatting-only updates. |
| example/index.js | Formatting-only updates. |
| example/babel.config.js | Formatting-only updates. |
| example/app.json | Formatting-only updates. |
| example/android/gradlew.bat | Removes redundant CLASSPATH usage when invoking wrapper jar. |
| example/android/gradlew | Removes unused CLASSPATH wiring for wrapper invocation. |
| example/android/gradle/wrapper/gradle-wrapper.properties | Updates Gradle wrapper distribution URL. |
| example/Gemfile | Adds nkf gem dependency. |
| example/.prettierrc.js | Removes Prettier config in favor of Biome. |
| example/.eslintrc.js | Removes ESLint config in favor of Biome. |
| eslint.config.mts | Removes ESLint flat config (Biome migration). |
| docs/HOOKS.md | Documents new useKeyRotation hook. |
| biome.json | Adds Biome formatter/linter configuration and overrides. |
| babel.config.js | Formatting-only updates. |
| app.plugin.js | Formatting-only updates. |
| android/src/main/java/com/sensitiveinfo/internal/util/SensitiveInfoExceptions.kt | Adds integrity-violation exception code/message. |
| android/src/main/java/com/sensitiveinfo/internal/util/AliasGenerator.kt | Embeds key version in Keystore aliases; adds HMAC alias helper. |
| android/src/main/java/com/sensitiveinfo/internal/storage/PersistedMetadata.kt | Persists key version + integrity tag in Android metadata. |
| android/src/main/java/com/sensitiveinfo/internal/storage/PersistedEntry.kt | Persists key version/AAD flag/integrity tag for Android entries. |
| android/src/main/java/com/sensitiveinfo/internal/storage/KeyVersionRegistry.kt | Adds Android key version registry backed by SharedPreferences. |
| android/src/main/java/com/sensitiveinfo/internal/crypto/MetadataIntegrity.kt | Adds Android per-entry HMAC signing/verification (Keystore-backed). |
| android/src/main/java/com/sensitiveinfo/internal/crypto/CryptoManager.kt | Adds optional AES-GCM AAD, plaintext zeroization, device-unlock requirement. |
| README.md | Updates docs for new hook/error subpaths, key rotation, security model, tree-shaking. |
| CHANGELOG.md | Adds Unreleased 6.0.0-rc.13 notes and breaking-change callouts. |
| .release-it.json | Formatting-only updates. |
| .prettierrc.js | Removes Prettier config in favor of Biome. |
Comments suppressed due to low confidence (7)
package.json:1
CHANGELOG.mdand the PR description refer to6.0.0-rc.13, butpackage.jsonstill reports6.0.0-rc.12. Please align the package version with the release candidate referenced in the PR (or update the changelog/description if the version bump is intentionally deferred).
src/hooks/useSecureStorage.ts:1- The effect (and its comment) implies
localItemsshould reset when a fresh fetch result arrives, but with an empty dependency array it runs only once on mount. This can leavelocalItemspermanently overridingfetchQuery.dataafter mutations (e.g.,removeSecret) or after option/service changes. Update the dependency list to key off the fetch result (for examplefetchQuery.data/ a fetch counter) so the local override is cleared when new server/native data lands.
src/errors.ts:1 extractMessagedrops useful messages from non-Errorobjects (for example{ code: 'E_INTEGRITY_VIOLATION', message: 'oops' }), causingtoSensitiveInfoError()to emit generic fallback text even when a specific message is available. Consider also reading a stringmessagefield from plain objects to preserve native error detail.
ios/Internal/Security/MetadataIntegrity.swift:1- If
SecItemAddreturnserrSecDuplicateItem(possible under cross-process races between the lookup and add), this currently returns a brand-new random key (rawKey) instead of loading and returning the already-stored key. That would cause HMAC verification failures for entries created with the existing key. OnerrSecDuplicateItem, re-fetch the key from the Keychain (or retrySecItemCopyMatching) and return the stored key instead.
ios/HybridSensitiveInfo.swift:1 - Integrity tag generation errors are silently swallowed (
try?), which can result in writing new entries without anintegrityTag(making them indistinguishable from legacy entries and disabling tamper detection for those writes). Consider failing the write when HMAC key creation/signing fails, or at least surfacing an explicit error so callers don’t get a false sense of integrity coverage.
example/src/components/KeyRotationPanel.tsx:1 - The “Rotate + re-encrypt all” button triggers the same
rotate()call as the lazy path, but the hook is instantiated with{ service }(noreEncryptEagerly: true), so eager rotation is never actually requested. Either create a seconduseKeyRotation({ service, reEncryptEagerly: true }), or update the hook API to accept per-call options so the eager button can passreEncryptEagerly: true.
ios/Internal/Security/MetadataIntegrity.swift:1 NSLockis not a recursive lock. Either switch toNSRecursiveLock(if re-entrancy is required) or update the comment to avoid implying recursion guarantees that the implementation doesn’t provide.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…-encryption support
Co-authored-by: Copilot <copilot@github.com>
….json and nitro.json
…used components - Introduced AccessControlCard for managing access modes with visual feedback. - Added DiagnosticsCard to display security availability and key version information. - Removed ActionButton, ActionsPanel, Card, Header, KeyRotationPanel, ModeSelector, SecretForm, SecretsList, and formatError utility as they were no longer needed. - Updated constants to streamline access modes and added biometric prompt configuration. - Enhanced StorageCard to manage secure storage with improved UI and functionality. - Introduced Section and StatusLine components for better layout and error handling. - Updated TypeScript configuration to include hooks and errors paths for improved module resolution. Co-authored-by: Copilot <copilot@github.com>
…or subpath imports
Split option handling into readOptions/writeOptions via resolveOptions and update components to use them (Storage, KeyRotation, Diagnostics, AccessControl). Add reusable Button and Footer components and a useAsyncAction hook. Improve Storage UI: reveal-with-TTL, async actions for save/reveal/delete/clear, item list with badges, and better loading/status handling. Adjust AccessControl to show capability labels and fallback state for unavailable biometry. Update KeyRotation/Diagnostics to use imperative getKeyVersion and avoid unnecessary auth prompts. Replace manual memset_s zeroization with Data.resetBytes on iOS. Tweak tsconfig for bundler module resolution and stricter checks. Also add GITHUB_URL constant and minor style/UX polish across the example app.
Add extensive JSDoc, examples and type refinements across the library. Introduces a SensitiveInfoApi facade, documents all core APIs (setItem/getItem/hasItem/deleteItem/getAllItems/clearService/getSupportedSecurityLevels/rotateKeys/getKeyVersion) with params, returns, errors and examples. Expands and documents typed error classes and predicates in errors.ts, improves hook-related types and helpers (HookError, AsyncState, mutation results) in hooks/types.ts, clarifies useSecureStorage usage docs, and enriches the Nitro interface and payload types in sensitive-info.nitro.ts (SecurityLevel, AccessControl, request/response shapes, StorageMetadata). Also updates package root docs and quick-start in index.ts. Changes are primarily documentation and typing improvements; no behavioral changes intended.
Add comprehensive JSDoc to useSecret and useSecretItem to clarify parameters, return shapes, and behavior. Highlights: useSecret now documents that it combines a read subscription with saveSecret/deleteSecret that refresh the cache on success and that mutation helpers return a discriminated HookMutationResult (do not throw). useSecretItem docs explain includeValue:false (metadata-only, avoids iOS biometric prompt), that NotFoundError is surfaced as data:null, and include usage examples and @see references. No functional changes — only documentation improvements.
Add comprehensive JSDoc comments to useHasSecret, useKeyRotation, useSecureOperation, and useSecurityAvailability. The updates document params, return types, remarks, examples, and related links; clarify behaviors such as avoiding biometric prompts when only checking existence, lazy vs eager key rotation and its biometric implications, execute() swallowing errors and exposing AuthenticationCanceledError as a cause, and caching/refetch semantics for security capability queries. Improves developer guidance and API discoverability.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This pull request introduces a major release candidate (6.0.0-rc.13) with significant new features, security hardening, and developer experience improvements. The most important changes include the addition of versioned key rotation with lazy re-encryption, a comprehensive defense-in-depth pass (including per-entry HMAC integrity tags and AES-GCM AAD binding), new typed error classes, and a migration from Prettier/ESLint to Biome for formatting and linting. The documentation and API surface have also been updated to reflect these changes, including the removal of the default export and improved tree-shaking support.
Key management and security enhancements:
rotateKeys()andgetKeyVersion(), with lazy or eager re-encryption. A newuseKeyRotationReact hook exposes this flow declaratively. (CHANGELOG.md[1]README.md[2] [3]android/src/main/java/com/sensitiveinfo/internal/storage/KeyVersionRegistry.kt[4]android/src/main/java/com/sensitiveinfo/internal/storage/PersistedEntry.kt[5] [6] [7]IntegrityViolationError. (CHANGELOG.md[1]README.md[2]android/src/main/java/com/sensitiveinfo/internal/crypto/MetadataIntegrity.kt[3]android/src/main/java/com/sensitiveinfo/internal/storage/PersistedEntry.kt[4] [5] [6]service|key|v<version>, preventing cross-entry swap attacks. Device-unlocked state is required for all Keystore keys (API 28+), mirroring iOS semantics. (CHANGELOG.md[1]android/src/main/java/com/sensitiveinfo/internal/crypto/CryptoManager.kt[2] [3] [4] [5] [6]API and error handling improvements:
SensitiveInfoError,NotFoundError,AuthenticationCanceledError,IntegrityViolationError,KeyInvalidatedError,RotationFailedError) with discriminant codes andinstanceofpredicates, available from the/errorssubpath. (CHANGELOG.md[1]README.md[2]/hooks. (CHANGELOG.md[1]README.md[2] [3]Developer experience and documentation:
.prettierrc.jsfile was removed. (CHANGELOG.md[1].prettierrc.js[2]README.mdto cover key rotation, the security model, tree-shaking, and the new hook architecture. (README.md[1] [2] [3]These changes collectively advance the security, usability, and maintainability of the package, preparing it for a stable 6.0 release.